﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using CodeDemon.Models;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Configuration;

namespace CodeDemon.Controllers {
	public class BuilderController : ControllerBase {

		[RequiresAuthentication]
		public ActionResult Index( string defectID, string Title ) {
			// TODO: This is a hack with the session variables
			ReviewModel model = new ReviewModel();
			if (defectID != null)
			{
				model.CurrentDefectNumber = Int32.Parse(defectID);
			}
			model.VarHash.Add("Title", Title);
			PopulateModel(model);
			return View( "Index", model );
		}

		[RequiresAuthentication]
		public ActionResult DisplayRevisions(string DefectID)
		{
			// create review
			ReviewModel model = new ReviewModel();
			int realDefectID = 0;
			realDefectID = Int32.Parse(DefectID);

			model.CurrentDefectNumber = realDefectID;
			PopulateModel( model );
			// read the file list
			return View("DisplayRevisions", model);
		}

		[RequiresAuthentication]
		public ActionResult DisplayRevisionFiles(int RevisionID)
		{
			ReviewModel model = new ReviewModel();
			model.CurrentRevisionNumber = RevisionID;
			return View("DisplayRevisionFiles", model);
		}

		[RequiresAuthentication]
		public ActionResult CreateReview(string Title, string Description, string DefectID, string[] reviewers, string[] cclist, string[] logID_list )
		{
			ReviewModel reviewModel = new ReviewModel();
			int realDefectID = 0;
			if (DefectID != null)
			{
				realDefectID = Int32.Parse(DefectID);
			}


			reviewModel.CreateReview(Title, Description, realDefectID, CurrentLoggedInReviewUserID);
			// TODO: This is a hack with writing the session variables

			// log the creation
			reviewModel.DAO.AddReviewLogEntry(reviewModel.CurrentReviewID, "Review Created", DateTime.Now, CurrentLoggedInReviewUserID, null);
			reviewModel.CurrentDefectNumber = realDefectID;
			int reviewId = reviewModel.CurrentReviewID;

			PopulateModel( reviewModel );
			int changeSetCounter = 0;
			int fileCounter = 0;
			foreach (string changeSet in logID_list)
			{
				int parsedChangeSet = 0;
				if(!Int32.TryParse(changeSet, out parsedChangeSet) ) {
					continue;
				}
				changeSetCounter++;
				var revision = (from rev in reviewModel.DAO.GetSVNLogByLogID(parsedChangeSet) select rev).FirstOrDefault();
				var revisionRepo = (from repos in reviewModel.DAO.GetSVNRepositoryByID(revision.RepositoryID) select repos).FirstOrDefault();
				//var revision = (from rev in reviewModel.DAO.SVNLog where rev.Revision == Int32.Parse(changeSet) select rev).FirstOrDefault();

				// TODO: Add Revision to Review Link Table Entry
				using (Process p2 = new Process()) {
					p2.StartInfo.UseShellExecute = false;
					p2.StartInfo.CreateNoWindow = true;
					p2.StartInfo.FileName = ConfigurationManager.AppSettings["SVNDiffBatch"].ToString();
					Guid myGuide = System.Guid.NewGuid();
					string ApplicationFilePath = System.Web.Hosting.HostingEnvironment.MapPath( @"~/App_Data" );
					string diffPath = System.IO.Path.Combine( ApplicationFilePath, myGuide.ToString() + ".diff" );

					p2.StartInfo.Arguments = revision.Revision + @" " + revisionRepo.RepositoryURL + " " + diffPath;
					p2.Start();
					p2.WaitForExit();
					#region DiffParser
					StringBuilder sb = new StringBuilder( string.Empty );
					using (FileStream inputStream = new FileStream( diffPath, FileMode.Open, FileAccess.Read )) {
						using (StreamReader streamReader = new StreamReader( inputStream )) {

							while (!streamReader.EndOfStream) {
								sb.Append( streamReader.ReadLine() + Environment.NewLine );
							};
							streamReader.Close();
							inputStream.Close();

							// this is a changeset

							string markeredOutput = Regex.Replace( sb.ToString(), @"^Index: ", "XXXXSPLITTERXXXXIndex: ", RegexOptions.Multiline );
							string[] diffs = Regex.Split( markeredOutput, @"^XXXXSPLITTERXXXX",RegexOptions.Multiline );
							foreach (string diff in diffs) {
								if (diff == String.Empty) {
									continue;
								}
								fileCounter++;
								// get filename
								Regex matcher = new Regex( "^Index: (?<FILE_NAME>.*)" );
								// TODO: Add Parsing for Property Changes
								Match mymatches = matcher.Match( diff );
								string fileName = mymatches.Groups["FILE_NAME"].ToString();
								fileName = @"/" + fileName.Replace( "\r", "" );
								System.Xml.XmlReader xRead = System.Xml.XmlReader.Create( new System.IO.StringReader( revision.LogXml ) );
								System.Xml.Linq.XDocument xDoc = System.Xml.Linq.XDocument.Load( xRead );
								var svnLogEntryPath = (from path in xDoc.Descendants( "path" ) where fileName == path.Value select path).FirstOrDefault();
								//TODO: Copy From Will Break The Log Parser
								string logMessage = revision.LogMessage;
								Regex regex = new Regex(ConfigurationManager.AppSettings["RegexForDefectInLogMessage"].ToString());
								Match myMatch = regex.Match( logMessage );
								int defectNumber = 0;
								if (myMatch != null)
								{
									defectNumber = Int32.Parse(myMatch.Groups["BUG_ID"].Value);
								}
								// is this a binary file?
								bool isBinary = false;
								Regex binMatcher = new Regex("^Cannot display: file marked as a binary type.", RegexOptions.Multiline);
								Match binMatches = binMatcher.Match(diff);
								if (binMatches.Success)
								{
									isBinary = true;
								}

								reviewModel.InsertReviewFile(reviewId, diff, fileName, revision.Revision.Value, logMessage, revision.Author, svnLogEntryPath.Attribute("action").Value.Replace(" ", ""), revision.Date.ToString(), defectNumber, isBinary, revision.RepositoryID.Value);
							}
						}
					}
					System.IO.File.Delete( diffPath );
					#endregion DiffParser
					reviewModel.InsertRevisionReview(Int32.Parse(changeSet), reviewId);
				}
			}

			// log the creation
			//reviewModel.InsertReviewLogEntry( reviewId, String.Format( "Added {0} change sets and {1} files to review", changeSetCounter, fileCounter ) );
			// update the review status

			//string[] reviewerIds = reviewers.Split( ',' );
			foreach (string r in reviewers)
			{
				try {
					reviewModel.InsertReviewParticipant( reviewId, Int32.Parse( r ), true );
				}
				catch { }
			}

			// add CClist
			if (cclist != null )
			{
				//string[] ccIds = cclist.Split(',');
				foreach (string c in cclist)
				{
					try
					{
						reviewModel.InsertReviewParticipant(reviewId, Int32.Parse(c), false);
					}
					catch { }
				}
			}

			reviewModel.UpdateStatus(reviewId, "NEW", CurrentLoggedInReviewUserID);
			reviewModel.SendCreateAlert( reviewId );
			return Redirect("/CodeDemon/Review/DisplayReview?reviewID=" + reviewId);
		}
	}
}
